package com.ins.service.impl;


import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.ins.common.exception.ServerException;
import com.ins.common.utils.TokenUtils;
import com.ins.mapper.AppInfoMarketMapper;
import com.ins.mapper.AppUserMapper;
import com.ins.model.dto.TokenDTO;
import com.ins.model.dto.wx.LoginDTO;
import com.ins.model.dto.wx.WxUserInfoDTO;
import com.ins.model.entity.AppUser;
import com.ins.model.vo.AppUserVO;
import com.ins.secure.cache.TokenStoreCache;
import com.ins.service.AppUserService;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.crypto.digest.DigestUtil;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

import static com.ins.model.entity.table.AppUserTableDef.APP_USER;

/**
 * app用户表 服务层实现。
 *
 * @author ins
 * @since 2024-05-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> implements AppUserService {

    private final WxMaService wxMaService;

    private final TokenStoreCache tokenStoreCache;

    private final AppInfoMarketMapper appInfoMarketMapper;

    @Override
    public TokenDTO login(LoginDTO dto) {
        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(dto.code());
            // 用户信息校验
            log.info(">>>>>>> 微信返回sessionData：{}", session.toString());
            WxUserInfoDTO userInfo = dto.userInfo();
            if (!wxMaService.getUserService().checkUserInfo(session.getSessionKey(), userInfo.getRawData(), userInfo.getSignature())) {
                log.error("登录失败：数据签名验证失败");
                throw ServerException.spe("登录失败");
            }
            final String openId = session.getOpenid();
            // 解密用户信息
            final WxMaUserInfo wxMpUser = wxMaService.getUserService()
                                                     .getUserInfo(session.getSessionKey(), userInfo.getEncryptedData(), userInfo.getIv());
            log.info(">>>>>>> 解密用户信息：{}", wxMpUser.toString());
            final String account = RandomUtil.randomString(12);
            AppUser user = this.getOne(APP_USER.OPEN_ID.eq(openId));
            if (ObjUtil.isNotNull(user)) {
                user.setLastLoginTime(LocalDateTime.now());
                updateById(user);
            } else {
                AppUser newUser = AppUser.of().setUserName("微信用户" + account).setPassword(DigestUtil.md5Hex(openId)).setAccount(account)
                                         .setHasAut(0).setRegTime(LocalDateTime.now()).setAvatar(wxMpUser.getAvatarUrl());
                newUser.save();
                user = newUser;
            }
            String token = TokenUtils.generator();
            tokenStoreCache.saveUser(token, user);
            return new TokenDTO(token, user);
        } catch (WxErrorException e) {
            log.error("登录失败：调用微信接口失败", e);
            throw ServerException.spe("登录失败");
        }
    }

    @Override
    public AppUserVO getInfo(Long id) {
        Assert.notNull(id, () -> ServerException.spe("用户不存在"));
        AppUser user = getById(id);
        Assert.notNull(user, () -> ServerException.spe("用户不存在"));
        Integer likeNum = appInfoMarketMapper.countUserLikeNum(id);
        AppUserVO vo = BeanUtil.copyProperties(user, AppUserVO.class);
        vo.setLikeNum(likeNum);
        return vo;
    }
}